import json
from openhtf import Test
from openhtf.util import data

from openhtf.core.test_record import TestRecord
from openhtf.core.test_state import TestState
from time import sleep
import threading

def _get_executing_test():
    """Get the currently executing test and its state."""
    tests = list(Test.TEST_INSTANCES.values())

    if not tests:
        return None, None

    if len(tests) > 1:
        pass

    test = tests[0]
    test_state = test.state

    if test_state is None:
        return None, None

    return test, test_state

def _get_executing_tests():
    """Get the currently executing tests and state."""
    tests = list(Test.TEST_INSTANCES.values())
    if not tests:
        return None

    return [ (test,test.state) for test in tests]


def get_test(test_id):
    for _,test_state in _get_executing_tests():
        test_state_dict,event = _to_dict_with_event(test_state)
        if test_state_dict["execution_uid"] == test_id:
            return _,test_state
    return None

def _to_dict_with_event(test_state: TestState):
    """Process a test state into the format we want to send to the frontend."""
    original_dict, event = test_state.asdict_with_event()

    # This line may produce a 'dictionary changed size during iteration' error.
    test_state_dict = data.convert_to_base_types(original_dict)

    test_state_dict["execution_uid"] = test_state.execution_uid
    return test_state_dict, event

def get_tests_with_metadata():
    tests = []
    for _,test_state in _get_executing_tests():
        test_state_dict,event = _to_dict_with_event(test_state)
        tests.append({test_state_dict["execution_uid"]:test_state_dict})
    return tests


class SimpleStationWatcher(threading.Thread):
    """
    Simplified watcher that detects phase changes and sends test state updates.
    """

    def __init__(self, execution_uid ,send_update_callback):
        super().__init__(daemon=True)
        self.execution_uid = execution_uid
        self.send_update = send_update_callback
        self.previous_state = None
        self.stop_event = threading.Event()

    def run(self):
        while not self.stop_event.is_set():
            tests = _get_executing_tests()
            for _,test_state in tests:
                if test_state.execution_uid != self.execution_uid:
                    continue
                if test_state is not None:
                    # TODO: Add a hash to result of _to_dict_with_event to speed up comparaison
                    test_state_dict, _ = _to_dict_with_event(test_state)
                    if test_state_dict != self.previous_state:
                        self.send_update(test_state_dict)
                        self.previous_state = test_state_dict
                sleep(0.1)  # Wait for 100 milliseconds

    def stop(self):
        self.stop_event.set()